<?php
/**
 * dbModel.php
 * This file holds the rules and settings for database, acts as our orm as well
 *
 * @author Peter, Thomas, Tryggve
 * @version 0.1
 * @copyright Oh, yes!
 * @package default
 */

 // We must have the db-settings
require_once('common/dbSettings.php') ;

/**
 * @package default
 * @subpackage classes
 */
class DbModel {

    private $m_mysqli = null ;

    /**
     * __construct
     * 
     * @return void
     */
    public function __construct() {
        $this->m_mysqli = new mysqli(DbSettings::DB_HOST, DbSettings::DB_USER, DbSettings::DB_PASSWORD, DbSettings::DB_DATABASE) ;
    }
	
    /**
     * connect 
     * 
     * @return boolean
     */
    public function connect() {
        $this->m_mysqli = new mysqli( 
            Config::$dbHost, 
            Config::$dbUser, 
            Config::$dbPassword, 
            Config::$dbDatabase
        ) ;

        // setting charset
        $this->m_mysqli->set_charset('utf8') ;

        // throw exception if it yealds any errors
        if($this->m_mysqli->connect_errno) {
            throw new exception($this->m_mysqli->connection_error) ;
            return false ;
        }
        return true ;

    }

    /**
     * close 
     * close the db-connection
     * 
     * @return void
     */
    public function close() {
        return $this->m_mysqli->close() ;
    }
	
    /**
     * prepare 
     * 
     * @param string $sql 
     * 
     * @return 
     */
    public function prepare($a_sql) {

        if($this->m_mysqli){
            $stmt = $this->m_mysqli->prepare($a_sql);
        } else {
            echo "fail!" ;
            return FALSE ;
        }
        if ($stmt === FALSE) {
	    echo("prepare of '$a_sql' failed " . $this->m_mysqli->error);
	    return FALSE;
	}
	return $stmt;
    }

   /**
    * get
    * 
    * @param Object $a_class Object to save result in
    * @param string $a_tableName
    * 
    * @return array With objects
    * 
    */
    public function get($a_tableName, $a_class, $a_where = "") {

        $query = "SELECT * FROM $a_tableName $a_where" ;

        $stmt = $this->prepare($query) ;

       	return $this->runAndFetchObjects($stmt, $a_class) ;

    }
    /**
     * addObjectToTable 
     * 
     * @param string $a_tableName
     * @param Object $a_object 
     * 
     * @return void
     */
    public function addObjectToTable($a_tableName, $a_object) {
        
        // Get the variables from the object and remove those who are null        
        $objectVars = get_object_vars($a_object) ;
		$objectVars = array_filter($objectVars, 'strlen');
		
		// start the variables we are going to use to build this string from the object
        $rows = "(" ;
        $values = "(" ;
        $types = "" ;
        $parameters = array() ;
        
        // get the keys (variable names) and the last one so we know when to stop
        $keys = array_keys($objectVars) ;
        $lastKey = end($keys) ;
        
        // for each public variable in the object
        foreach ($objectVars as $key => $value) {
                
            // get the mysqli-type
            $getType = $this->getType($value) ;   
            
            // if we get a parsable type
            if ($getType !== false) {
                // add the things to the strings
                $types .= $getType ;    
                $rows .= $key ;
                $values .= "?" ;
                // add the values to an array
                $parameters[] = $value ;
                
                // if it isn't the last we have to append a comma and a space on each
                if($key !== $lastKey) {
                    $values .= ", " ;
                    $rows .= ", " ;
                }
            }
        }

        // rows and values should end with a parantesis
        $rows .= ")" ;
        $values .= ")" ;

        // and build the query from the strings
        $query = "INSERT INTO $a_tableName $rows VALUES $values" ;
        $stmt = $this->prepare($query) ;

        return $this->bindParamAndExecute($stmt, $types, $parameters) ;

    }

	/**
     * runAndFetchObject 
     * 
     * @param mysqli_stmt $a_stmt 
     * @param string $a_class 
     * 
     * @return array Whith objects
     */
    private function runAndFetchObjects(mysqli_stmt $a_stmt, $a_class) {
        $respArray = array() ;
        $a_stmt->execute() ;
        $response = $a_stmt->get_result() ;
        
        while($resp = $response->fetch_object($a_class)) {
        	
			$respArray[] = $resp ;
			
        }
        
        return $respArray ;

    }
    
    /**
     * update
     * 
     * @param String $a_where The sql-where statement, eg 'WHERE id = 1'
     * @param String $a_tableName 
     * @param Object $a_object The object to update
     */

    public function update($a_where, $a_tableName, $a_object) {

        // Get the variables from the object, remove null and void and empty strings
        $objectVars = get_object_vars($a_object) ;
        $objectVars = array_filter($objectVars, 'strlen');

        // start the strings and arrays that we are going to use
        $keys = "" ;
        $types = "" ;
        $parameters = array() ;
        
        // Check for last key in array
        $arrayKeys = array_keys($objectVars) ;
        $lastKey = end($arrayKeys) ;
        foreach ($objectVars as $key => $value) {

	        // get the mysqli-type
            $getType = $this->getType($value) ; 
            
            // if it is parasable by getType, build the array
            if ($getType !== FALSE) {
                $types .= $getType ;
	            $keys .= $key." = ?" ;
	            $parameters[] = $value ;
	            
	            
                // if it isn't last, we have to append a comma
	            if($key !== $lastKey) {
	                $keys .= ", " ;
	            }
	        }

        
        }
        
        // build query
        $query = "UPDATE $a_tableName SET $keys $a_where" ;

        // prepare
        $stmt = $this->prepare($query) ;

        // and bind_param from array and execute stmt.
        return $this->bindParamAndExecute($stmt, $types, $parameters) ;


    }
    // To be implemented
    public function delete($where, $table) {

        $sql = "DELETE FROM $table $where" ;
        $stmt = $this->prepare($sql) ;
        
        if($stmt->execute()) {
            return true ;
        }
        return false ;
    }
    /**
     * getType
     * Get the mysqli-type 
     * 
     * @access private
     * 
     * @param string $a_string
     * 
     * @return false|string
     */
    private function getType($a_string) {
        
        switch (gettype($a_string)) {
                    
            case "integer":
                return "i" ;
            case "string":
                return "s" ;
            case "double":
                return "d" ;
            default: 
                return false ;
        }
    }

    /**
     * bindParamAndExecute
     * Function to call bindParam from an array of parameters instead of string
     * 
     * @access private
     * 
     * @param mysqli_stmt $a_stmt
     * @param string $a_types The mysqli types
     * @param array $a_parameters An array with the parameters to save to db
     * 
     * @return boolean
     * 
     */
    private function bindParamAndExecute(mysqli_stmt $a_stmt, $a_types, $a_parameters) {
        // Now is time for some bad voodo-magic. We first have to merge the array with the types and the parameters
        // So that we can send an array to the bind_param function
        $param = array_merge(array($a_types), $a_parameters);

        // $stmt->bind_param don't expect strings, so we have to make a tmp-array with pointers to the $param array...
        $tmp = array();
        foreach($param as $key => $value) $tmp[$key] = &$param[$key];
        
        // then we use call_use_func_array so that we can send an array to $stmt->bind_param instead of strings
        if (!call_user_func_array(array($a_stmt,"bind_param"), $tmp)) {
            echo("bind_param failed " . $a_stmt->error);
            return false;
        }

        // execute the statement
        return $a_stmt->execute() ;
    }
}
